package cc.jq1024.trigger.http;

import cc.jq1024.domain.activity.service.IRaffleActivityAccountQuotaService;
import cc.jq1024.domain.strategy.model.entity.RaffleAwardEntity;
import cc.jq1024.domain.strategy.model.entity.RaffleFactorEntity;
import cc.jq1024.domain.strategy.model.entity.StrategyAwardEntity;
import cc.jq1024.domain.strategy.model.valobj.RuleWeightVO;
import cc.jq1024.domain.strategy.service.IRaffleAward;
import cc.jq1024.domain.strategy.service.IRaffleRule;
import cc.jq1024.domain.strategy.service.IRaffleStrategy;
import cc.jq1024.domain.strategy.service.armory.IStrategyArmory;
import cc.jq1024.trigger.api.IRaffleStrategyService;
import cc.jq1024.trigger.api.dto.*;
import cc.jq1024.types.enums.ResponseCode;
import cc.jq1024.types.exception.AppException;
import cc.jq1024.types.model.Response;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @Author: jia-qiang ljq1024.cc
 * @desc: 抽奖接口实现， 也是暴露给外部的controller
 * @Date: 2024-04-20-15:53
 */
@Slf4j
@AllArgsConstructor
@RestController("raffle_controller")
@RequestMapping("/raffle/strategy/")
@DubboService(version = "${dubbo.application.version}")
@CrossOrigin(value = {"${app.config.cross-origin:http://116.198.239.101:3000/}", "http://localhost:3000/"})
public class RaffleStrategyController implements IRaffleStrategyService {

    /** 策略装配 */
    private final IStrategyArmory strategyArmory;
    /** 策略奖品相关 */
    private final IRaffleAward raffleAward;
    /** 抽奖策略相关 */
    private final IRaffleStrategy raffleStrategy;
    /** 策略规则 */
    private final IRaffleRule raffleRule;
    /** 用户额度相关 */
    private final IRaffleActivityAccountQuotaService raffleActivityAccountQuotaService;

    /**
     * 策略装配接口
     * <a href="http://localhost:8089/api/v1/raffle/strategy_armory">/api/v1/raffle/strategy_armory</a>
     *
     * @param strategyId 策略ID
     * @return 装配结果
     */
    @Override
    @RequestMapping(value = "strategy_armory", method = RequestMethod.GET)
    public Response<Boolean> strategyArmory(@RequestParam("strategyId") Long strategyId) {
        try {
            log.info("策略装配开始, strategyId: {}", strategyId);
            boolean armoryStatus = strategyArmory.assembleLotteryStrategy(strategyId);
            Response<Boolean> response = Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(armoryStatus)
                    .build();
            log.info("策略装配结束, strategyId: {} armoryStatus: {}", strategyId, armoryStatus);
            return response;

        } catch (Exception e) {
            log.error("策略装配失败, strategyId: {}", strategyId, e);
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 查询奖品列表
     * <a href="http://localhost:8089/api/v1/raffle/query_raffle_award_list">/api/v1/raffle/query_raffle_award_list</a>
     *
     * @param request 参数 {"strategyId":1000001}
     * @return 奖品列表
     */
    @Override
    @RequestMapping(value = "query_raffle_award_list", method = RequestMethod.POST)
    public Response<List<RaffleAwardListResponseDTO>> queryRaffleAwardList(@RequestBody RaffleAwardListRequestDTO request) {
        try {
            log.info("查询抽奖奖品列表配开始 userId:{} activityId：{}", request.getUserId(), request.getActivityId());
            // 1. 参数校验
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }
            // 2. 查询奖品列表
            List<StrategyAwardEntity> strategyAwardEntities = raffleAward.queryRaffleStrategyAwardListByActivityId(request.getActivityId());
            // 3. 获取规则配置
            String[] treeIds = strategyAwardEntities.stream()
                    .map(StrategyAwardEntity::getRuleModels)
                    .filter(ruleModel -> ruleModel != null && !ruleModel.isEmpty())
                    .toArray(String[]::new);
            // 4. 查询规则配置 - 获取奖品的解锁限制，抽奖N次后解锁
            Map<String, Integer> ruleLockCountMap = raffleRule.queryAwardRuleLockCount(treeIds);
            // 5. 查询抽奖次数 - 用户今日已经参与的抽奖次数
            Integer dayPartakeCount = raffleActivityAccountQuotaService.queryRaffleActivityAccountDayPartakeCount(request.getActivityId(), request.getUserId());
            // 6. 遍历填充数据
            List<RaffleAwardListResponseDTO> raffleAwardListResponseDTOS = new ArrayList<>(strategyAwardEntities.size());
            for (StrategyAwardEntity strategyAward : strategyAwardEntities) {
                Integer awardRuleLockCount = ruleLockCountMap.get(strategyAward.getRuleModels());
                raffleAwardListResponseDTOS.add(RaffleAwardListResponseDTO.builder()
                        .awardId(strategyAward.getAwardId())
                        .awardTitle(strategyAward.getAwardTitle())
                        .awardSubtitle(strategyAward.getAwardSubtitle())
                        .sort(strategyAward.getSort())
                        .awardRuleLockCount(awardRuleLockCount)
                        .isAwardUnlock(null == awardRuleLockCount || dayPartakeCount >= awardRuleLockCount)
                        .waitUnLockCount(null == awardRuleLockCount || awardRuleLockCount <= dayPartakeCount ? 0 : awardRuleLockCount - dayPartakeCount)
                        .build());
            }
            // 7. 构造返回结果
            Response<List<RaffleAwardListResponseDTO>> response = Response.<List<RaffleAwardListResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleAwardListResponseDTOS)
                    .build();
            log.info("查询抽奖奖品列表配置完成 userId:{} activityId：{} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
            // 8. 返回结果
            return response;

        } catch (Exception e) {
            log.error("查询策略奖品列表失败, activityId: {}", request.getActivityId(), e);
//            throw new RuntimeException(e);
            return Response.<List<RaffleAwardListResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 查询抽奖策略权重规则，给用户展示出抽奖N次后必中奖奖品范围
     *
     * @param request 请求对象
     * @return 权重奖品配置列表「这里会返回全部，前端可按需展示一条已达标的，或者一条要达标的」
     */
    @Override
    @RequestMapping(value = "query_raffle_strategy_rule_weight", method = RequestMethod.POST)
    public Response<List<RaffleStrategyRuleWeightResponseDTO>> queryRaffleStrategyRuleWeight(@RequestBody RaffleStrategyRuleWeightRequestDTO request) {
        try {
            log.info("查询抽奖策略权重规则配置开始 userId:{} activityId：{}", request.getUserId(), request.getActivityId());
            // 1. 参数校验
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }
            // 2. 查询用户抽奖总次数
            Integer userActivityAccountTotalUseCount = raffleActivityAccountQuotaService.queryRaffleActivityAccountPartakeCount(request.getActivityId(), request.getUserId());
            // 3. 查询规则信息
            List<RuleWeightVO> ruleWeightVOList = raffleRule.queryAwardRuleWeightByActivityId(request.getActivityId());
            // 4. 转换对象
            List<RaffleStrategyRuleWeightResponseDTO> raffleStrategyRuleWeightList = this.getRaffleStrategyRuleWeightResponseDTOS(ruleWeightVOList, userActivityAccountTotalUseCount);
            Response<List<RaffleStrategyRuleWeightResponseDTO>> response = Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(raffleStrategyRuleWeightList)
                    .build();
            log.info("查询抽奖策略权重规则配置完成 userId:{} activityId：{} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            log.error("查询抽奖策略权重规则配置失败 userId:{} activityId：{}", request.getUserId(), request.getActivityId(), e);
            return Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }
    /**
     * 将 List<RuleWeightVO> 转换为 List<RaffleStrategyRuleWeightResponseDTO>
     */
    private List<RaffleStrategyRuleWeightResponseDTO> getRaffleStrategyRuleWeightResponseDTOS(List<RuleWeightVO> ruleWeightVOList, Integer userActivityAccountTotalUseCount) {
        List<RaffleStrategyRuleWeightResponseDTO> raffleStrategyRuleWeightList = new ArrayList<>(ruleWeightVOList.size());
        for (RuleWeightVO ruleWeightVO : ruleWeightVOList) {
            List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> strategyAwards = this.getStrategyAwards(ruleWeightVO);

            // 封装对象
            RaffleStrategyRuleWeightResponseDTO raffleStrategyRuleWeightResponseDTO = new RaffleStrategyRuleWeightResponseDTO();
            raffleStrategyRuleWeightResponseDTO.setRuleWeightCount(ruleWeightVO.getWeight());
            raffleStrategyRuleWeightResponseDTO.setStrategyAwards(strategyAwards);
            raffleStrategyRuleWeightResponseDTO.setUserActivityAccountTotalUseCount(userActivityAccountTotalUseCount);

            raffleStrategyRuleWeightList.add(raffleStrategyRuleWeightResponseDTO);
        }
        // 排序
        raffleStrategyRuleWeightList.sort(Comparator.comparingInt(RaffleStrategyRuleWeightResponseDTO::getRuleWeightCount));
        return raffleStrategyRuleWeightList;
    }
    /**
     * 将 ruleWeightVO中的List<Award></Award> 对象转为 List<RaffleStrategyRuleWeightResponseDTO.StrategyAward>
     */
    private List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> getStrategyAwards(RuleWeightVO ruleWeightVO) {
        List<RuleWeightVO.Award> awardList = ruleWeightVO.getAwardList();
        if (null == awardList || awardList.isEmpty()) return Collections.emptyList();
        List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> strategyAwards = new ArrayList<>(awardList.size());
        for (RuleWeightVO.Award award : awardList) {
            RaffleStrategyRuleWeightResponseDTO.StrategyAward strategyAward = new RaffleStrategyRuleWeightResponseDTO.StrategyAward();
            strategyAward.setAwardId(award.getAwardId());
            strategyAward.setAwardTitle(award.getAwardTitle());
            strategyAwards.add(strategyAward);
        }
        return strategyAwards;
    }

    /**
     * 随机抽奖接口
     * <a href="http://localhost:8091/api/v1/raffle/random_raffle">/api/v1/raffle/random_raffle</a>
     *
     * @param requestDTO 请求参数 {"strategyId":1000001}
     * @return 奖品信息
     */
    @Override
    @RequestMapping(value = "random_raffle", method = RequestMethod.POST)
    public Response<RaffleStrategyResponseDTO> randomRaffle(@RequestBody RaffleStrategyRequestDTO requestDTO) {
        try {
            log.info("随机抽奖开始 strategyId: {}", requestDTO.getStrategyId());
            // 调用抽奖接口
            RaffleAwardEntity raffleAwardEntity = raffleStrategy.preformRaffle(RaffleFactorEntity.builder()
                    .userId("system")
                    .strategyId(requestDTO.getStrategyId())
                    .build());
            // 封装返回结果
            Response<RaffleStrategyResponseDTO> response = Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(RaffleStrategyResponseDTO.builder()
                            .awardId(raffleAwardEntity.getAwardId())
                            .awardIndex(raffleAwardEntity.getSort())
                            .build())
                    .build();
            log.info("随机抽奖完成 strategyId: {} response: {}", requestDTO.getStrategyId(), JSON.toJSONString(response));
            return response;
        } catch (AppException e) {
            log.error("随机抽奖失败 strategyId：{} {}", requestDTO.getStrategyId(), e.getInfo());
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .build();
        } catch (Exception e) {
            log.error("随机抽奖失败 strategyId：{}", requestDTO.getStrategyId(), e);
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

}
